////////////////////////////////////////////////
// DESCRIPTION:
//    Sample SPI device emulator component
//
// Legal Notices:
//   Copyright (c) 2008, Telliam Consulting, LLC.
//   All rights reserved.
//
//   Redistribution and use in source and binary forms, with or without modification,
//   are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice, this list
//     of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice, this
//     list of conditions and the following disclaimer in the documentation and/or other
//     materials provided with the distribution.
//   * Neither the name of Telliam Consulting nor the names of its contributors may be
//     used to endorse or promote products derived from this software without specific
//     prior written permission.
//
//   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//   SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
//   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
//   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//   DAMAGE. 
//
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.Generic;

using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Emulator;
using Microsoft.SPOT.Emulator.Spi;
using Microsoft.SPOT.Emulator.Gpio;

namespace FusionWare.SPOT.EmulatorComponents
{
    /// <summary>This is a demonstration of an emulated SPI Device</summary>
    /// <remarks>
    /// The device emulated here has a simple protocol. This device suports
    /// one command to read the "Chip ID". Sending the ReadID command (0x5A)
    /// will return the 2 byte ChipID (0xAA55) in little-endian order.
    /// </remarks>
    public class SimpleSPIDevice : SpiDevice
    {
        /// <summary>Creates a new SimpleSPIDevice instance</summary>
        public SimpleSPIDevice() 
        {
            this._ChipID = 0xAA55;
            this.SpiModule = Spi.SpiModule.Spi1;
            this.ChipSelectActiveState = false;
            this.ChipSelectHoldTime = 1;
            this.ChipSelectSetupTime = 1;
            this.ClockIdleState = false;
            this.ClockEdge = true;
            this.ClockRateKHz = 16000;
        }

        /// <summary>ChipID read from the configuration file</summary>
        /// <remarks>This is an optional value. If not present the default
        /// 0xAA55, set in the constructor, is used.</remarks>
        public ushort ChipID
        {
            get { return this._ChipID; }
            set
            {
                base.ThrowIfNotConfigurable();
                this._ChipID = value;
            }
        }
        private ushort _ChipID;

        /// <summary>Name of the pin to use for this devices chip select</summary>
        public string PinName
        {
            get
            {
                return base.Emulator.GpioPorts[ this.ChipSelectPin ].ComponentId;
            }
            set
            {
                GpioPort ssPin = (GpioPort)base.Emulator.FindComponentById(value);
                if(ssPin == null)
                {
                    ssPin = new GpioPort();
                    ssPin.ComponentId = value;
                    ssPin.Pin = ((CustomEmulator)Emulator).GetPinByName(value);
                    ssPin.ModesAllowed = GpioPortMode.InputOutputPort;
                    ssPin.ModesExpected = GpioPortMode.InputOutputPort;
                    Emulator.RegisterComponent(ssPin);
                }
                this.ChipSelectPin = ssPin.Pin;
            }
        }

        /// <summary>Writes data to the device</summary>
        /// <param name="data">data being written to this device</param>
        /// <returns>array of bytes read from the device</returns>
        protected override byte[] Write(byte[] data)
        {
            // current MS emulator implementation requires symmetrically sized
            // read and write buffers therefore this requires a 2 byte write
            // command but ignores the second byte.
            if(data.Length < 1 || (data[0] != 0x5A))
                throw new ArgumentException("Invalid Length","data");

            byte[] retVal = new byte[2];            
            retVal[0] = (byte)(this._ChipID & 0xFF);
            retVal[1] = (byte)(this._ChipID >> 8);
#if DEBUG
            System.Windows.Forms.MessageBox.Show(string.Format("retval[0]=0x{0:X2} retval[1]=0x{1:X2}", retVal[0], retVal[1]), "Chip ID");
#endif
            return retVal;
        }
    }
}
